﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using SpreadsheetGear;
using WorkbookDesigner.Addons.SpreadsheetEditor.Model;
using WorkbookDesigner.Addons.SpreadsheetEditor.UI;
using DesignerHelper.Help;
using DesignerHelper.Main;

namespace WorkbookDesigner.Addons.SpreadsheetEditor.Presenter
{
    public class MainPresenter : ISpreadEditorPresenter
    {

        public MainPresenter(ISpreadEditorView view) : this(Factory.GetWorkbookSet())
        {
            View = view;

            Wbv.ActiveWorkbookSet = Wbs;
            Wbs.GetLock();
            Wbv.ActiveWorkbook = Wbs.Workbooks[0];
            Wbs.ReleaseLock();
            InitPresenter();
        }

        public MainPresenter(ISpreadEditorView view, IWorkbookSet wbs) : this(wbs)
        {
            View = view;
            InitPresenter();
        }
        private MainPresenter(IWorkbookSet wbs)
        {
            Wbs = wbs;
            TemplateModel = new TemplateModel(Wbs);
            Wbs.GetLock();

            Wbs.DefaultFontName = "微软雅黑";
            Wbs.DefaultFontSize = 11;
            IWorkbook testbook = Wbs.Workbooks.Add();
            Wbs.ReleaseLock();
        }

        private void InitPresenter()
        {
            MPresenter = new MissionPresenter(Wbs, View.MissionView, View.BookView);
            View.MissionView.Presenter = MPresenter;
            View.BookView.Presenter = MPresenter;
            View.BackgroundWorker.DoWork += BackrgroundHandler;
            View.BackgroundWorker.RunWorkerCompleted += BackgroundComplete;
        }
        public TemplateModel TemplateModel { get; private set; }
        private MissionPresenter MPresenter { get; set; }


        public ISpreadEditorView View { get; }

        private TreeView BaseTreeView => View.FileTreeView;
        private SpreadsheetGear.Windows.Forms.WorkbookView Wbv => View.BookView.ActiveView;


        private IWorkbookSet Wbs { get; set; }
        public void ExecuteAll()
        {
            Task task = new Task(Execute);
            task.Start();
        }

        private void Execute()
        {
            Wbs.DoWork(() =>
            {
                ProgressBar bar = View.ProgressBar;
                int count = View.FileTreeView.Nodes.OfType<IMissionSet>().Sum(missionSet => missionSet.MissionList.Count)
                            * MPresenter.AllAction.Count;
                Action init = () =>
                {
                    bar.Value = bar.Minimum;
                    bar.Maximum = count;
                    bar.Step = 1;
                    bar.Style = ProgressBarStyle.Continuous;

                };
                bar.BeginInvoke(init);
                Action step = bar.PerformStep;
                for (int i = 0; i < MPresenter.AllAction.Count; i++)
                {
                    var actionModel = MPresenter.AllAction[i];
                    foreach (IMissionSet missionSet in View.FileTreeView.Nodes.OfType<IMissionSet>())
                    {
                        foreach (IMission mission in missionSet.MissionList)
                        {
                            mission.SyncPrompts();
                            actionModel.Execute(mission);
                            bar.BeginInvoke(step);
                        }
                    }
                    //MPresenter.AllAction.Remove(actionModel);//ps 可选判断execute是否成功后决定是否移除
                    //i--;
                }
                Action report = () =>
                {
                    MesBox.InfoMessage($"操作完成,共执行 {count} 个操作");
                    bar.Value = bar.Minimum;
                };
                bar.BeginInvoke(report);
            });
            Action ss = () => View.MissionView.ResetListViewSize();
            View.MissionView.ActionViews.BeginInvoke(ss);
            MPresenter.AllAction.Clear();
        }


        private void OrganizeFiles()
        {
            string[] paths;
            using (OpenFileDialog dia = Business.GetOpenFileDialog(TemplateModel.GetDirectoryInfo().Parent?.FullName ?? TemplateModel.Directory))
            {
                if (dia.ShowDialog() != DialogResult.OK) return;
                paths = dia.FileNames;
            }
            IEnumerable<FileInfo> fileList = paths.Select(path => new FileInfo(path));
            FileInfo file0 = new FileInfo(paths[0]);
            DirectoryInfo dir = file0.Directory;

            ReorganizeTreeview(dir, fileList);

        }


        private void OrganizeFolder()
        {
            string path;
            using (FolderBrowserDialog dia = Business.GetFolderBrowserDialog($@"{TemplateModel.Directory}", "请选择要批量操作的文件夹"))
            {
                if (dia.ShowDialog() != DialogResult.OK) return;
                path = dia.SelectedPath;
            }
            DirectoryInfo dir = new DirectoryInfo(path);
            var fileList =
                dir.EnumerateFiles("*", SearchOption.TopDirectoryOnly)//ps 搜索子集目录
                .Where(fileInfo => fileInfo.Extension.Equals(".cutx"));
            ReorganizeTreeview(dir, fileList);

        }

        private void ReorganizeTreeview(DirectoryInfo dir, IEnumerable<FileInfo> fileList)
        {
            TreeNode dirNode = BaseTreeView.Nodes.GetDirectoryNode(dir);
            var mset = dirNode.GetMissionSet();

            var toAdd = fileList.Where(info => dirNode.Nodes.OfType<IMission>().All(x => !x.FileInfo.FullName.Equals(info.FullName))).Select(MissionHelper.GetFileNode);

            //mset.MissionList.AddRange(toAdd);
            dirNode.Nodes.AddRange(toAdd.ToArray());
        }
        #region Helper Class

        private static class Business
        {
            internal static FolderBrowserDialog GetFolderBrowserDialog(string selectedPath, string description)
            {
                return new FolderBrowserDialog()
                {
                    SelectedPath = selectedPath,
                    Description = description,
                };
            }

            internal static OpenFileDialog GetOpenFileDialog(string initialDirectory)
            {
                return new OpenFileDialog
                {
                    CheckFileExists = true,
                    CheckPathExists = true,
                    // ReSharper disable once LocalizableElement
                    Filter = "产品文件(*.cutx)|*.cutx",
                    Multiselect = true,
                    InitialDirectory = initialDirectory,
                    // ReSharper disable once LocalizableElement
                    Title = "请选择要编辑的文件"
                };
            }
        }

        #endregion


        #region View EventHandler

        public void OnBtn_SelectTemplateDir_Click()
        {
            using (FolderBrowserDialog dialog = Business.GetFolderBrowserDialog(/*@"D:\MyDocument\Visual Studio 2015\DesignerProject\Library\v4"*/
                    @"G:\WoodEngine产品库\缔盟产品库", "请选择产品库目录"))
            {
                if (TemplateModel.Loaded)
                    TemplateModel.CloseAll();
                switch (dialog.ShowDialog())
                {
                    case DialogResult.OK:
                        if (TemplateModel.LoadFiles(dialog.SelectedPath))
                            View.EnableView();
                        else
                            View.DisableView();
                        break;
                    default:
                        TemplateModel.Reset();
                        View.DisableView();
                        break;
                }
            }
        }

        public void OnTreeView_AfterCheck(TreeViewEventArgs e)
        {
            //View.BackgroundWorker.DoWork += BackrgroundHandler;
            //View.BackgroundWorker.RunWorkerCompleted += BackgroundComplete;
            if (e.Action == TreeViewAction.Unknown)
                return;
            TreeNode node = e.Node;
            //BackgroundWorker bw = View.BackgroundWorker;
            //bw.RunWorkerAsync(node);
            Action<TreeNode> action = AwTest;
            Task task = new Task(() => action(node));
            task.Start();
        }

        public void OnTreeView_NodeMouseClick(TreeNodeMouseClickEventArgs e)
        {
            if (e.Node.Level == 0) return;
            var mission = e.Node.GetMission();
            if (!mission.Loaded) return;
            Wbv.GetLock();
            IWorkbook book = mission.Workbook;
            Wbv.ActiveWorkbook = book;
            View.MissionView.ShowMissionDetail(mission);
            Wbv.ReleaseLock();
        }

        public void OnViewClosing(FormClosingEventArgs e)
        {
            Wbs.GetLock();
            if (TemplateModel.Loaded)
                TemplateModel.CloseAll();
            //foreach (IMissionSet set in View.FileTreeView.Nodes.OfType<IMissionSet>())
            //{
            //    foreach (IMission m in set.MissionList)
            //    {
            //        m.UnLoad(false);
            //    }
            //}
            Wbs.Workbooks.Close();
            Wbs.ReleaseLock();
        }
        #region File Operation
        public void OnAddDirectory()
        {
            OrganizeFolder();
        }

        public void OnBtnAddFiles_Click()
        {
            OrganizeFiles();
        }
        public void OnBtnRemove_Click()
        {
            TreeNode node = BaseTreeView.SelectedNode;
            if (node == null) return;
            View.MissionView.ResetListViewSize();
            switch (node.Level)
            {
                case 1:
                    IMission mission = node.GetMission();
                    Wbs.GetLock();
                    MissionTransact(mission, false);
                    Wbs.ReleaseLock();
                    break;
                case 0:
                    IMissionSet mset = node.GetMissionSet();
                    Wbs.GetLock();
                    foreach (var m in mset.Missions)
                    {
                        MissionTransact(m, false);
                    }
                    Wbs.ReleaseLock();
                    //UnloadMissionSet(mset);
                    node.Nodes.Clear();
                    break;
            }
            node.Remove();
        }

        public void OnBtnSelectAll_Click()
        {
            var nodes = BaseTreeView.Nodes;
        }

        public void OnBtnSaveAll_Click()
        {
            Task task = new Task(SaveAll);
            task.Start();
        }

        private void SaveAll()
        {
            Wbs.GetLock();
            try
            {
                ProgressBar bar = View.ProgressBar;
                int count = View.FileTreeView.Nodes.OfType<IMissionSet>().Sum(x => x.MissionList.Count);
                Action init = () =>
                {
                    bar.Value = bar.Minimum;
                    bar.Maximum = count;
                    bar.Step = 1;
                    bar.Style = ProgressBarStyle.Continuous;
                };
                bar.BeginInvoke(init);
                Action step = bar.PerformStep;
                foreach (IMissionSet missionSet in View.FileTreeView.Nodes.OfType<IMissionSet>())
                {
                    foreach (IMission mission in missionSet.MissionList)
                    {
                        mission.Save();
                        bar.BeginInvoke(step);
                    }
                }
                MesBox.InfoMessage($"工作簿保存完成");
                bar.BeginInvoke(init);
            }
            finally
            {
                Wbs.ReleaseLock();
            }
        }
        #endregion
        private void MissionTransact(IMission m, bool toLoad)
        {
            IMissionSet mset = m.MissionSet;
            if (!toLoad && mset.MissionList.Contains(m) && m.Loaded)
            {
                m.UnLoad();//工作簿close比较耗时
                mset.MissionList.Remove(m);
            }
            else if (toLoad && !mset.MissionList.Contains(m) && !m.Loaded)
            {
                m.Load(Wbs.Workbooks);
                mset.MissionList.Add(m);
            }
        }
        #endregion

        #region OnTreeViewCheck

        private void BackgroundComplete(object sender, RunWorkerCompletedEventArgs e)
        {
            //var bw = sender as BackgroundWorker;
            //if (bw != null) bw.DoWork -= BackrgroundHandler;
        }

        private void BackrgroundHandler(object sender, DoWorkEventArgs e)
        {
            var node = e.Argument as TreeNode;
            if (node == null) return;
            Wbs.GetLock();
            switch (node.Level)
            {
                case 0:
                    foreach (IMission mission in node.Nodes.OfType<IMission>())
                    {
                        Action check = () => mission.Checked = node.Checked;
                        MissionTransact(mission, node.Checked);
                        View.BeginInvoke(check, null);
                    }
                    break;
                case 1:
                    //IMissionSet mset = MissionHelper.GetMissionSet(node.Parent);
                    IMission m = node.GetMission();
                    MissionTransact(m, node.Checked);
                    break;
            }
            Wbs.ReleaseLock();
        }

        private void AwTest(TreeNode node)
        {
            if (node == null) return;
            Wbs.GetLock();
            switch (node.Level)
            {
                case 0:
                    foreach (IMission mission in node.Nodes.OfType<IMission>())
                    {
                        Action check = () => mission.Checked = node.Checked;
                        MissionTransact(mission, node.Checked);
                        View.BeginInvoke(check, null);
                    }
                    break;
                case 1:
                    //IMissionSet mset = MissionHelper.GetMissionSet(node.Parent);
                    IMission m = node.GetMission();
                    MissionTransact(m, node.Checked);
                    break;
            }
            Wbs.ReleaseLock();

        }
        #endregion

        private void CallBack(IAsyncResult result)
        {

        }
    }
}
